//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.example.wechat.login.filter;

import com.example.wechat.login.util.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import java.io.IOException;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Collections;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
    private final JwtUtil jwtUtil;
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    @Value("${jwt.header}")
    private String tokenHeader;
    @Value("${jwt.prefix}")
    private String tokenPrefix;
    @Value("#{'${jwt.exclude-paths}'.split(',')}")
    private List<String> excludePaths;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String string = request.getRequestURL().toString();
        logger.debug("请求路径：{}", string);
        if (this.shouldSkipAuthentication(request)) {
            logger.debug("跳过认证");
            filterChain.doFilter(request, response);
        } else {
            try {
                String jwt = this.getJwtFromRequest(request);
                if (!StringUtils.hasText(jwt)) {
                    logger.warn("未提供JWT令牌");
                    response.setStatus(401);
                    response.getWriter().write("未提供认证令牌");
                    return;
                }

                String openid = this.jwtUtil.getOpenidFromToken(jwt);
                request.setAttribute("openid", openid);
                
                // 创建认证对象并设置到SecurityContextHolder
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    openid, null, Collections.emptyList());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                
                logger.debug("JWT认证成功，openid: {}", openid);
            } catch (ExpiredJwtException e) {
                logger.warn("JWT令牌已过期", e);
                response.setStatus(401);
                response.getWriter().write("认证令牌已过期");
                return;
            } catch (UnsupportedJwtException | SignatureException | MalformedJwtException e) {
                logger.warn("无效的JWT令牌", e);
                response.setStatus(401);
                response.getWriter().write("无效的认证令牌");
                return;
            } catch (Exception e) {
                logger.error("JWT认证失败", e);
                response.setStatus(401);
                response.getWriter().write("认证失败");
                return;
            }

            filterChain.doFilter(request, response);
        }
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader(this.tokenHeader);
        return StringUtils.hasText(bearerToken) && bearerToken.startsWith(this.tokenPrefix) ? bearerToken.substring(this.tokenPrefix.length()).trim() : null;
    }

    private boolean shouldSkipAuthentication(HttpServletRequest request) {
        String requestPath = request.getServletPath();
        logger.debug("请求路径requestPath：{}", requestPath);
        for(String pattern : this.excludePaths) {
            if (this.pathMatcher.match(pattern.trim(), requestPath)) {
                return true;
            }
        }

        return false;
    }
}
